#ifndef QUERRY_H
#define QUERY_H

#include <pqxx/pqxx>
#include "fusexx.h"

#define MAX_SQL_BUF 100000    //!< maximum length of the sql quieries. defaults to 100000
#define MAX_WRITE_CHUNK 1024 * 1024

class PostgreDB {
public:

/**
 * Takes a full path and returnes the inode and/or id corresponding to the path at the "tree" table in the database through 
 * the inode and/or id parameters.  
 * @param inode if NULL is given, no value is returned
 * @param id if null is given, no value is returned
 * 
 * \return on error: -ENOENT(no tree entry corresponding to path),-EIO(I/O error) \n on sucess: 0
 */
    static int query_inode_full(pqxx::connection* conn, const char* path, int* inode, int* id);

/**
 * Calls query_inode_full 
 * 
 * \return on error: -ENOENT(no tree entry corresponding to path),-EIO(I/O error) \n on sucess: inode
 */
    static int query_inode(pqxx::connection* conn, const char* path);    

/**
 * Calls query_inode_full 
 * 
 * \return on error: -ENOENT(no tree entry corresponding to path),-EIO(I/O error) \n on sucess: id
 */
    static int query_id(pqxx::connection* conn, const char* path);

/**
 * Looks up the inode in the "inodes" table and returns the size column
 * 
 * \return on error: -EIO(I/O error) \n on sucess: size
 */
    static ssize_t query_size(pqxx::connection* conn, int inode);

/**
 * Looks up the inode in the "inodes" table and sets the size column 
 * 
 * \return on error: -EIO(I/O error) \n on sucess: 0
 */
    static int query_set_size(pqxx::connection* conn, int inode, int size);

/**
 * Adds new entry to the "inodes" table 
 * 
 * \return on error: -EIO(I/O error) \n on sucess: inode
 */
    static int query_mknod(pqxx::connection* conn, const char* name, mode_t mode, \
                           dev_t dev, int parent);

/**
 * Looks up the inode in the "inodes" table and returns the attrubutes of the file through the stbuf parameter
 * 
 * \return on error: -EIO(I/O error) \n on sucess: 0
 */
    static int query_getattr(pqxx::connection* conn, int inode, struct stat* stbuf);

/**
 * Returns the contents of a dir through the buf parameter. The information is written by the fuse_fill_dir_t filler 
 * function
 * 
 * \return on error: -EIO(I/O error) \n on sucess: 0
 */
    static int query_readdir(pqxx::connection* conn, int dir_id, void* buf, \
                             fuse_fill_dir_t filler);

/**
 * Increases the inuse counter in the "inodes" table
 * 
 * \return on error: -EIO(I/O error) \n on sucess: 0
 */
    static int query_inuse_inc(pqxx::connection* conn, int inode, int inc);

/**
 * Updates the atime and mtime attributes in the "inodes" table 
 * 
 * \return on error: -EIO(I/O error) \n on sucess: 0
 */
    static int query_utime(pqxx::connection* conn, int inode, struct utimbuf* time);

/**
 * Looks up the inode and updates the mode and the ctime columns in the 'inodes' table
 * 
 * \return on error: -EIO(I/O error) \n on sucess: 0
 */
    static int query_chmod(pqxx::connection* conn, int inode, mode_t mode);

/**
 * Looks up the inode in the "inodes" table and updates the uid, gid and ctime attributes
 * 
 * \return on error: -EIO(I/O error) \n on sucess: 0
 */
    static int query_chown(pqxx::connection* conn, int inode, uid_t uid, gid_t gid);

/**
 * Returns the oid corresponding to the given id in the 'inodes' table through the data_oid parameter
 * 
 * \return on error: -EIO(I/O error) \n on sucess: 0
 */
    static int query_get_data_oid(pqxx::connection* conn, int inode, int* data_oid);

/**
 * Changes the size of a file. Truncate to smaller size!=0 is not yet supprted! \n 
 * If the file size is increased zeroes are written to the end. The inode size in the "inodes" table is changed.
 * 
 * \return on error: -EIO(I/O error) \n on sucess: 0
 */
    static int query_truncate(pqxx::connection* conn, int inode, off_t size);

/**
 * 
 * Gets the oid using query_get_data_oid and writes to the LargeObject.
 * 
 * \return on error: -EIO(I/O error) \n on sucess: number of bytes written
 */
    static int query_write(pqxx::connection* conn, int inode, const char* data, \
                           size_t size, off_t offset);

/**
 * 
 * Gets the oid using query_get_data_oid and reads from the LargeObject.
 * 
 * \return on error: -EIO(I/O error) \n on sucess: number of bytes read
 */
    static int query_read(pqxx::connection* conn, int inode, char* data, \
                          size_t size, off_t offset);

/**
 * 
 * \return on error: -EIO(I/O error) \n on sucess: 0
 */
    static int query_rm_tree_entry(pqxx::connection* conn, int tree_id);

/**
 * 
 * Deletes a marked for deleting (with flag "deleted" in the "inodes" table set to 1) file from the "inodes" table if 
 * it is not in use
 * 
 * \return on error: -EIO(I/O error) \n on sucess: number of bytes written
 */
    static int query_purge_deleted(pqxx::connection* conn, int inode);

};

//*********************************** WriteLargeObject Class **************************************
class WriteLargeObject : public pqxx::transactor<> {

private:
    pqxx::largeobject my_object;
    int data_oid;
    const char* data;
    size_t size;
    off_t offset;

    size_t* new_size;

public:
    WriteLargeObject(int data_oid, const char* data, size_t size, off_t offset, size_t* new_size);

    void operator()(argument_type& T);
};

//*********************************** ReadLargeObject Class **************************************
class ReadLargeObject : public pqxx::transactor<> {

private:
    pqxx::largeobject my_object;
    int data_oid;
    char* data;
    size_t size;
    off_t offset;
public:
    ReadLargeObject(int oid, char* data, size_t size, off_t offset);

    void operator()(argument_type& T);

};


#endif
